#include <pthread.h>
#include <signal.h>
#include <hardware/gps.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>

/* CURL Stuff 
  #include <libcurl/inc/curl.h>
  #include <string.h>
*/

#define WAKE_LOCK_NAME  "GPS"
const GpsInterface* gGpsInterface = NULL;

char fileName[] = "/data/gpscoords.log";
FILE *fp;
char url[] = "http://serengeti.gmu.edu/coordinator/store.php";
int recCount;
int maxRecCount = 50;

// Remove log file
int removeLogFile()
{
  int status;
  status = remove(fileName);
 
  if( status == 0 ) {
    printf("%s file deleted successfully.\n",fileName);
    return 0;
  }
  else
  {
    printf("Unable to delete the file\n");
    perror("Error");
    return 1;
  }
}

// Append to log file
int appendLogFile(float lat, float lon, float spd, long ts)
{
  if ((fp = fopen(fileName, "a")) == NULL) {
    printf("\twritet2File - failed to append file: %s\n", fileName);
    return 1;
  }
  else {
    fprintf(fp, "%f, %f, %f, %ld\n", lat, lon, spd, ts);
    fclose(fp);
    return 0;
  }
}

// Create a log file for keeping gps info

int createLogFile()
{
  if ((fp = fopen(fileName, "w")) == NULL) {
    printf("\twritet2File - failed to create file: %s\n", fileName);
    return 1;
  }
  else {
    return 0;
  }
}

// CURL function to upload coordinates to remote server
int sendCoordinates(float lat, float lon, float spd, float ts) 
{
  system("curl --data "lat=lat&lon=long&spd=spd&ts=ts" url");
  return 0;
}

static const GpsInterface* get_gps_interface()
{
  fprintf(stdout, "* Executing: get_gps_interface() *\n");

  int err;
  hw_module_t* module;
  const GpsInterface* interface = NULL;

  err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);

  if (!err) {
    hw_device_t* device;
    err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device);
    if (!err) {
      gps_device_t* gps_device = (gps_device_t *)device;
      interface = gps_device->get_gps_interface(gps_device);
    }
  }
  
  if (err) {
    fprintf(stdout, "*** Failed to create GPS interface*\n");
  }

  return interface;
}

static void location_callback(GpsLocation* location)
{
  fprintf(stdout, "+---------------------------------------------+\n");
  fprintf(stdout, "|  *** GPS Location Information ***           |\n");
  fprintf(stdout, "+---------------------------------------------+\n");
  fprintf(stdout, "| flags:\t%d\n", location->flags);
  fprintf(stdout, "| lat:  \t%lf\n", location->latitude);
  fprintf(stdout, "| long: \t%lf\n", location->longitude);
  fprintf(stdout, "| speed: \t%lf\n", location->speed);
  fprintf(stdout, "| bearing: \t%lf\n", location->bearing);
  fprintf(stdout, "| accur:\t%f\n", location->accuracy);
  fprintf(stdout, "| utc:  \t%ld\n", (long)location->timestamp);
  fprintf(stdout, "+---------------------------------------------+\n");
  
  sendCoordinates(location->latitude, location->longitude, location->speed,
                  location->timestamp);

}

static void status_callback(GpsStatus* status)
{
  // fprintf(stdout, "* Executing: status_callback() *\n");

  switch (status->status) {
  case GPS_STATUS_NONE:
    fprintf(stdout, "*** no gps\n");
    break;
  case GPS_STATUS_SESSION_BEGIN:
    fprintf(stdout, "*** session begin\n");
    break;
  case GPS_STATUS_SESSION_END:
    fprintf(stdout, "*** session end\n");
    break;
  case GPS_STATUS_ENGINE_ON:
    fprintf(stdout, "*** engine on\n");
    break;
  case GPS_STATUS_ENGINE_OFF:
    fprintf(stdout, "*** engine off\n");
    break;
  default:
    fprintf(stdout, "*** unknown status\n");
  }
}

static void sv_status_callback(GpsSvStatus* sv_info)
{
 /*
  fprintf(stdout, "* Executing: sv_status_callback() *\n");
  fprintf(stdout, "*** sv info\n");
  fprintf(stdout, "num_svs:\t%d\n", sv_info->size);
 */
}

static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
{
 /*
  fprintf(stdout, "* Executing: nmea_callback() *\n");
  fprintf(stdout, "*** nmea info\n");
  fprintf(stdout, "timestamp:\t%ld\n", (long)timestamp);
  fprintf(stdout, "nmea:     \t%s\n", nmea);
  fprintf(stdout, "length:   \t%d\n", length);
 */

}

static void set_capabilities_callback(uint32_t capabilities)
{
 /*
  fprintf(stdout, "* Executing: set_capabilities_callback() *\n");
  fprintf(stdout, "*** set capabilities\n");
 */

}

static void acquire_wakelock_callback()
{
 /*
  fprintf(stdout, "* Executing: acquire_wakelock_callback() *\n");
  // acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
 */
}

static void release_wakelock_callback()
{
 /*
  fprintf(stdout, "* Executing: release_wakelock_callback() *\n");
  // release_wake_lock(WAKE_LOCK_NAME);
 */
}

static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
{
  // fprintf(stdout, "* Executing: create_thread_callback() *\n");

  //GpsLocation* locationX;
  
  pthread_t thread;
  pthread_attr_t attr;
  int err;

  err = pthread_attr_init(&attr);
  err = pthread_create(&thread, &attr, (void*(*)(void*))start, arg);

  // location_callback(callbacks);
  
  return thread;
}

// Create an instance of the struct GpsCallbacks
GpsCallbacks callbacks = {
  sizeof(GpsCallbacks),
  location_callback,
  status_callback,
  sv_status_callback,
  nmea_callback,
  set_capabilities_callback,
  acquire_wakelock_callback,
  release_wakelock_callback,
  create_thread_callback,
};


void sigint_handler(int signum)
{
  // fprintf(stdout, "* Executing: sigint_handler() *\n");

  fprintf(stdout, "*** cleanup\n");
  if (gGpsInterface) {
    gGpsInterface->stop();
    gGpsInterface->cleanup();
  }
}

int main(int argc, char *argv[])
{
  // fprintf(stdout, "* Executing: main *\n");

  // fprintf(stdout, "  ** setup signal handler\n");
  signal(SIGINT, sigint_handler);

  // fprintf(stdout, "*** get gps interface\n");
  gGpsInterface = get_gps_interface();

  fprintf(stdout, "*** init gps interface\n");
  
  if (gGpsInterface && !gGpsInterface->init(&callbacks)) {
  
    fprintf(stdout, "*** start gps track\n");
    
    gGpsInterface->start();
    // timeval tv;
    // gettimeofday(&tv, NULL);
    // gGpsInterface->inject_time(tv.tv_sec, tv.tv_sec, 0);
    gGpsInterface->set_position_mode(GPS_POSITION_MODE_STANDALONE,
                                     GPS_POSITION_RECURRENCE_PERIODIC,
                                     1000, 0, 0);
                                     
  }

  else {
    fprintf(stdout, "*** Failed to gps track\n");
  }

  sleep(10000000);
  return 0;
}
